package org.hroze.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;
/**
 * zip解压、压缩工具类
 * 
 * @author ahoo
 * @since 2010-09-21
 * @version 0.1
 * @email ahoo@hroze.com
 * @host hroze.org
 */
public class Zip {

	private static final int BUFFEREDSIZE = 1024;
	/**
	 * zip工具类的单例
	 */
	private   static   Zip zipInstance;
	/**
	 * 压缩文件的字符编码
	 */
	public static String encoding="GBK";
	/**
	 * 
	 * 解压zip文件到指定文件夹
	 * 
	 * @param zipFileName
	 *            压缩文件
	 * 
	 * @param extPlace
	 *            解压目录
	 * @throws Exception 
	 * 
	 * @throws Exception
	 */

	public synchronized void unzip(String zipFileName, String extPlace) throws Exception{
		unzip(new File(zipFileName),new File(extPlace));
	}

	/**
	 * 
	 * 解压zip文件到指定文件夹
	 * 
	 * @param zipFileName
	 *            压缩文件
	 * 
	 * @param extPlace
	 *            解压目录
	 * 
	 * @throws Exception
	 */

	public synchronized void unzip(File zipFileName, File extPlace)
			throws Exception {
		try {

			extPlace.mkdirs();

			File f = zipFileName;

			ZipFile zipFile = new ZipFile(f, encoding);

			if ((!f.exists()) && (f.length() <= 0)) {

				throw new Exception("要解压的文件不存在!");

			}

			String strPath, gbkPath, strtemp;

			File tempFile = extPlace;

			strPath = tempFile.getAbsolutePath();

			java.util.Enumeration e = zipFile.getEntries();

			while (e.hasMoreElements()) {

				org.apache.tools.zip.ZipEntry zipEnt = (ZipEntry) e
						.nextElement();

				gbkPath = zipEnt.getName();

				if (zipEnt.isDirectory()) {

					strtemp = strPath + File.separator + gbkPath;

					File dir = new File(strtemp);

					dir.mkdirs();

					continue;

				} else {

					// 读写文件

					InputStream is = zipFile.getInputStream(zipEnt);

					BufferedInputStream bis = new BufferedInputStream(is);

					gbkPath = zipEnt.getName();

					strtemp = strPath + File.separator + gbkPath;

					// 建目录

					String strsubdir = gbkPath;

					for (int i = 0; i < strsubdir.length(); i++) {

						if (strsubdir.substring(i, i + 1).equalsIgnoreCase("/")) {

							String temp = strPath + File.separator
									+ strsubdir.substring(0, i);

							File subdir = new File(temp);

							if (!subdir.exists())

								subdir.mkdir();

						}

					}

					FileOutputStream fos = new FileOutputStream(strtemp);

					BufferedOutputStream bos = new BufferedOutputStream(fos);

					int c;

					while ((c = bis.read()) != -1) {

						bos.write((byte) c);

					}

					bos.close();

					fos.close();

				}

			}

		} catch (Exception e) {

			e.printStackTrace();

			throw e;

		}

	}

	
	/**
	 * 
	 * 将文件或者文件夹压缩为zip文件
	 * 
	 * @param inputFilename
	 *            压缩的文件或文件夹及详细路径
	 * 
	 * @param zipFilename
	 *            输出文件名称及详细路径
	 * 
	 * @throws IOException
	 */

	public synchronized void zip(String inputFilename, String zipFilename)
			throws IOException {

		zip(new File(inputFilename), zipFilename);

	}
	
	/**
	 * 
	 * 将多个文件或者文件夹压缩成指定名称的zip压缩文件
	 * 
	 * @param inputFile
	 *            需压缩文件
	 * 
	 * @param zipFilename
	 *            输出文件及详细路径
	 * 
	 * @throws IOException
	 */

	public synchronized void zip(String[] inputFile, String zipFilename)
			throws IOException {

		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
				zipFilename));
		out.setEncoding(encoding);
		try {
			for(String f :inputFile){
				File file=new File(f);
				zip(file, out, file.isDirectory()?file.getName():"");
			}
		} catch (IOException e) {

			throw e;

		} finally {

			out.close();

		}

	}
	/**
	 * 
	 * 将多个文件或者文件夹压缩成指定名称的zip压缩文件
	 * 
	 * @param inputFile
	 *            需压缩文件
	 * 
	 * @param zipFilename
	 *            输出文件及详细路径
	 * 
	 * @throws IOException
	 */

	public synchronized void zip(List<String> inputFile, String zipFilename)
			throws IOException {

		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
				zipFilename));
		out.setEncoding(encoding);
		try {
			for(String f :inputFile){
			File file=new File(f);
			zip(file, out, file.isDirectory()?file.getName():"");
			}
		} catch (IOException e) {

			throw e;

		} finally {

			out.close();

		}

	}
	/**
	 * 
	 * 将多个文件或者文件夹压缩成指定名称的zip压缩文件
	 * 
	 * @param inputFile
	 *            需要压缩的文件
	 * 
	 * @param zipFilename
	 *            压缩文件路径
	 * 
	 * @throws IOException
	 */

	public synchronized void zip(File[] inputFile, String zipFilename)
			throws IOException {

		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
				zipFilename));
		out.setEncoding(encoding);
		try {
			for(File f :inputFile)
			zip(f, out, f.isDirectory()?f.getName():"");
		} catch (IOException e) {

			throw e;

		} finally {

			out.close();

		}

	}
	
	/**
	 * 
	 * 将单个文件或者文件夹压为ZIP文件
	 * 
	 * @param inputFile
	 *            文件夹或者文件
	 * 
	 * @param zipFilename
	 *            压缩文件名称
	 * 
	 * @throws IOException
	 */

	public synchronized void zip(File inputFile, String zipFilename)
			throws IOException {

		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
				zipFilename));
		out.setEncoding(encoding);

		try {
			
			zip(inputFile, out, inputFile.isDirectory()?inputFile.getName():"");

		} catch (IOException e) {

			throw e;

		} finally {

			out.close();

		}

	}
	

	/**
	 * 
	 * 压缩zip格式的压缩文件
	 * 
	 * @param inputFile
	 *            需压缩文件
	 * 
	 * @param out
	 *            输出压缩文件
	 * 
	 * @param base
	 *            结束标识
	 * 
	 * @throws IOException
	 */

	private synchronized void zip(File inputFile, ZipOutputStream out,
			String base) throws IOException {

		if (inputFile.isDirectory()) {

			File[] inputFiles = inputFile.listFiles();

			out.putNextEntry(new ZipEntry(base + "/"));

			base = base.length() == 0 ? "" : base + "/";

			for (int i = 0; i < inputFiles.length; i++) {

				zip(inputFiles[i], out, base + inputFiles[i].getName());

			}

		} else {

			if (base.length() > 0) {

				out.putNextEntry(new ZipEntry(base));

			} else {

				out.putNextEntry(new ZipEntry(inputFile.getName()));

			}

			FileInputStream in = new FileInputStream(inputFile);

			try {

				int c;

				byte[] by = new byte[BUFFEREDSIZE];

				while ((c = in.read(by)) != -1) {

					out.write(by, 0, c);

				}

			} catch (IOException e) {

				throw e;

			} finally {

				in.close();

			}

		}

	}
	private Zip(){
		
	}
	/**
	 * 取得zip的单例
	 * @return
	 */
	public static Zip getZip(){
		if(zipInstance==null){
			zipInstance=new Zip();
		}
		return zipInstance;
	}

	public static void main(String[] args) throws Exception {
		//zip
		Zip zip =new Zip();
		zip.zip(new String[]{"d:\\a.txt","d:\\b.txt","d:\\c.txt","d:\\d"}, "d:\\m.zip");
		//unzip
		zip.unzip("d:\\m.zip", "d:\\zipm");
	}
}
